#pragma once

#include <iostream>
#include <memory>
#include "Epoller.hpp"
#include "Connection.hpp"
#include "Channel.hpp"
#include "./module/Socket.hpp"
#include "./module/comm.hpp"
using namespace SocketModule;

class Reactor;
// listener 专门用来获取新连接
class Listener : public Connection
{
public:
    Listener(uint32_t port = 8080)
        :_port(port)
        ,_listensockfd(std::make_unique<TcpSocket>())
    {
        _listensockfd->BuildTcpSocket(_port);
        // listensockfd只关心读事件, 将其设置为ET模式
        setEvents(EPOLLIN | EPOLLET);
        // 设置为ET模式后，需要将lisensockfd设置为非阻塞
        nonBlock(_listensockfd->Fd());
    }
    ~Listener(){}

    int getSockfd() { return _listensockfd->Fd(); }

    void recver() override
    {
        // 对于listensockfd来说，设置为ET模式后
        // 可能一次性有多个fd就绪，我们需要一次性全部读取上来
        InetAddr client;
        while(true) {
            int sockfd = _listensockfd->Accept(&client);
            if(sockfd == ACCEPT_OVER || sockfd == ACCEPT_ERROR)
                break;
            else if(sockfd == ACCEPT_CONTINUE)
                continue;
            else {
                // 到这里就是一个合法的文件描述符，为该文件描述符构建一个connection对象，并且添加到哈希表中
                std::shared_ptr<Connection> normal = std::make_shared<Channel>(sockfd, client);
                // 设置关心的事件
                normal->setEvents(EPOLLIN | EPOLLET);
                // 将回调方法设置给普通套接字
                if(_handler != nullptr)
                    normal->registerHandler(_handler);
                // 通过回指指针，调用server中的add方法，将该连接管理起来
                getPrivateData()->addConnection(normal);
            }
        }
    }
    void sender() override{}
    void excepter() override{}
private:
    uint32_t _port;
    std::unique_ptr<Socket> _listensockfd;
};